#include <kutils.h>
#include "irq.h"
#include "paging.h"
#include "display.h"
#include "task.h"
#include "keyboard.h"

void kbd_write_buffer(u8int scancode);
void kbd_wait_cmd(void);
void kbd_wait_ack(void);
void keyboard_handler(struct regs *r);

u32int caps = 0;
u32int num = 0;
u32int scrl = 0;
u32int ctrl = 0;
u32int alt = 0;
u32int key = 0;
u8int kbd_buffer[512];
u32int kbd_buffer_pos = 0;
u32int kbd_timeout = 10;
volatile u8int kbd_ack = 0;

void kbd_write_buffer(u8int scancode)
{
	if(kbd_buffer_pos < 512)
	{
		kbd_buffer[kbd_buffer_pos] = scancode;
		kbd_buffer_pos++;
	}
}

void kbd_clear_buffer(void)
{
	memset(kbd_buffer, 0, 512);
	kbd_buffer_pos = 0;
}

void kbd_wait_cmd(void)
{
	kbd_timeout = 10;
   while(kbd_timeout)
	{
		kbd_timeout--;
		if((inportb(0x64) & 0x01) == 0x00)
			return;
	}
	write_string("Keyboard: Output buffer full.\n");
}

void kbd_wait_ack(void)
{
	kbd_timeout = 10;
   while(kbd_timeout)
	{
		kbd_timeout--;
		if(kbd_ack)
		{
			kbd_ack = 0;
			return;
		}
	}
	write_string("Keyboard: Failed to ACK.\n");
}

void kbd_leds(u32int scrllck, u32int numlck, u32int capslck)
{
	kbd_wait_cmd();
	outportb(0x60, 0xED);
	kbd_wait_ack();

	kbd_wait_cmd();
	outportb(0x60, (u8int)(scrllck | numlck << 1 | capslck << 2)); 
	kbd_wait_ack();
}

void kbd_wait_key(void)
{
	key = 0;
	while(!key)
	{wait_interrupt();}
}

void keyboard_handler(struct regs *r)
{
	if(!r)
	{
		//something horribly bad...
		return;
	}

	u8int scancode;

   //Read from the keyboard's data buffer
	scancode = inportb(0x60);
	
	//note ACK's caught here.
	if(scancode == 0xFA)
	{
		kbd_ack = 1;
		return;
	}

	key = 1;
	kbd_write_buffer(scancode);
}

void init_kbd(void)
{
#ifdef FLUIDIUM_DEBUG
	write_string("Keyboard: Init\n");
#endif
   irq_install_handler(1, keyboard_handler);
}
